package com.mstar.qs.common.json;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;


public class JsonArray {
	/**
	 * The arrayList where the JSONArray's properties are kept.
	 */
	private final ArrayList myArrayList= new ArrayList();
	private Map<String, String> keymap; 
	private Set<String> excluded;


	public JsonArray(Collection collection, Map<String, String> keymap, Set<String> excluded) {
		this.keymap=keymap;
		this.excluded=excluded;
		if (collection != null) {
			Iterator iter = collection.iterator();
			while (iter.hasNext()) {
				Object o=JsonBean.wrap(iter.next(), keymap, excluded);
				if(o!=null)
				this.myArrayList.add(o);
			}
		}
	}
	
	public JsonArray(Object array, Map<String, String> keymap, Set<String> needed) throws JsonException {
		this.keymap=keymap;
		this.excluded=excluded;
		if (array.getClass().isArray()) {
			int length = Array.getLength(array);
			for (int i = 0; i < length; i += 1) {
				Object o=JsonBean.wrap(Array.get(array, i), keymap, needed);
				if(o!=null)
				this.put(o);
			}
		} else {
			throw new JsonException("JSONArray initial value should be a string or collection or array.");
		}
	}
	
	
	/**
	 * Append a boolean value. This increases the array's length by one.
	 * 
	 * @param value
	 *            A boolean value.
	 * @return this.
	 */
	public JsonArray put(boolean value) {
		this.put(value ? Boolean.TRUE : Boolean.FALSE);
		return this;
	}

	/**
	 * Put a value in the JSONArray, where the value will be a JSONArray which
	 * is produced from a Collection.
	 * 
	 * @param value
	 *            A Collection value.
	 * @return this.
	 */
	public JsonArray put(Collection value) {
		this.put(new JsonArray(value, keymap, excluded));
		return this;
	}

	/**
	 * Append a double value. This increases the array's length by one.
	 * 
	 * @param value
	 *            A double value.
	 * @throws JsonException
	 *             if the value is not finite.
	 * @return this.
	 */
	public JsonArray put(double value) throws JsonException {
		Double d = new Double(value);
		JsonBean.testValidity(d);
		this.put(d);
		return this;
	}

	/**
	 * Append an int value. This increases the array's length by one.
	 * 
	 * @param value
	 *            An int value.
	 * @return this.
	 */
	public JsonArray put(int value) {
		this.put(new Integer(value));
		return this;
	}

	/**
	 * Append an long value. This increases the array's length by one.
	 * 
	 * @param value
	 *            A long value.
	 * @return this.
	 */
	public JsonArray put(long value) {
		this.put(new Long(value));
		return this;
	}

	/**
	 * Put a value in the JSONArray, where the value will be a JSONObject which
	 * is produced from a Map.
	 * 
	 * @param value
	 *            A Map value.
	 * @return this.
	 */
	public JsonArray put(Map value) {
		this.put(new JsonBean(value, keymap,  excluded));
		return this;
	}

	/**
	 * Append an object value. This increases the array's length by one.
	 * 
	 * @param value
	 *            An object value. The value should be a Boolean, Double,
	 *            Integer, JSONArray, JSONObject, Long, or String, or the
	 *            JSONObject.NULL object.
	 * @return this.
	 */
	public JsonArray put(Object value) {
		this.myArrayList.add(value);
		return this;
	}

	/**
	 * Put or replace a boolean value in the JSONArray. If the index is greater
	 * than the length of the JSONArray, then null elements will be added as
	 * necessary to pad it out.
	 * 
	 * @param index
	 *            The subscript.
	 * @param value
	 *            A boolean value.
	 * @return this.
	 * @throws JsonException
	 *             If the index is negative.
	 */
	public JsonArray put(int index, boolean value) throws JsonException {
		this.put(index, value ? Boolean.TRUE : Boolean.FALSE);
		return this;
	}

	/**
	 * Put a value in the JSONArray, where the value will be a JSONArray which
	 * is produced from a Collection.
	 * 
	 * @param index
	 *            The subscript.
	 * @param value
	 *            A Collection value.
	 * @return this.
	 * @throws JsonException
	 *             If the index is negative or if the value is not finite.
	 */
	public JsonArray put(int index, Collection value) throws JsonException {
		this.put(index, new JsonArray(value, keymap, excluded));
		return this;
	}

	/**
	 * Put or replace a double value. If the index is greater than the length of
	 * the JSONArray, then null elements will be added as necessary to pad it
	 * out.
	 * 
	 * @param index
	 *            The subscript.
	 * @param value
	 *            A double value.
	 * @return this.
	 * @throws JsonException
	 *             If the index is negative or if the value is not finite.
	 */
	public JsonArray put(int index, double value) throws JsonException {
		this.put(index, new Double(value));
		return this;
	}

	/**
	 * Put or replace an int value. If the index is greater than the length of
	 * the JSONArray, then null elements will be added as necessary to pad it
	 * out.
	 * 
	 * @param index
	 *            The subscript.
	 * @param value
	 *            An int value.
	 * @return this.
	 * @throws JsonException
	 *             If the index is negative.
	 */
	public JsonArray put(int index, int value) throws JsonException {
		this.put(index, new Integer(value));
		return this;
	}

	/**
	 * Put or replace a long value. If the index is greater than the length of
	 * the JSONArray, then null elements will be added as necessary to pad it
	 * out.
	 * 
	 * @param index
	 *            The subscript.
	 * @param value
	 *            A long value.
	 * @return this.
	 * @throws JsonException
	 *             If the index is negative.
	 */
	public JsonArray put(int index, long value) throws JsonException {
		this.put(index, new Long(value));
		return this;
	}

	/**
	 * Put a value in the JSONArray, where the value will be a JSONObject that
	 * is produced from a Map.
	 * 
	 * @param index
	 *            The subscript.
	 * @param value
	 *            The Map value.
	 * @return this.
	 * @throws JsonException
	 *             If the index is negative or if the the value is an invalid
	 *             number.
	 */
	public JsonArray put(int index, Map value) throws JsonException {
		this.put(index, new JsonBean(value, keymap, excluded));
		return this;
	}

	/**
	 * Put or replace an object value in the JSONArray. If the index is greater
	 * than the length of the JSONArray, then null elements will be added as
	 * necessary to pad it out.
	 * 
	 * @param index
	 *            The subscript.
	 * @param value
	 *            The value to put into the array. The value should be a
	 *            Boolean, Double, Integer, JSONArray, JSONObject, Long, or
	 *            String, or the JSONObject.NULL object.
	 * @return this.
	 * @throws JsonException
	 *             If the index is negative or if the the value is an invalid
	 *             number.
	 */
	public JsonArray put(int index, Object value) throws JsonException {
		JsonBean.testValidity(value);
		if (index < 0) {
			throw new JsonException("JSONArray[" + index + "] not found.");
		}
		if (index < this.length()) {
			this.myArrayList.set(index, value);
		} else {
			while (index != this.length()) {
				this.put(JsonBean.NULL);
			}
			this.put(value);
		}
		return this;
	}
	
	/**
	 * Get the number of elements in the JSONArray, included nulls.
	 * 
	 * @return The length (or size).
	 */
	public int length() {
		return this.myArrayList.size();
	}
	

	/**
	 * Make a JSON text of this JSONArray. For compactness, no unnecessary
	 * whitespace is added. If it is not possible to produce a syntactically
	 * correct JSON text then null will be returned instead. This could occur if
	 * the array contains an invalid number.
	 * <p>
	 * Warning: This method assumes that the data structure is acyclical.
	 * 
	 * @return a printable, displayable, transmittable representation of the
	 *         array.
	 */
	public String toString() {
		try {
			return '[' + this.join(",") + ']';
		} catch (Exception e) {
			return null;
		}
	}
	
	/**
	 * Make a string from the contents of this JSONArray. The
	 * <code>separator</code> string is inserted between each element. Warning:
	 * This method assumes that the data structure is acyclical.
	 * 
	 * @param separator
	 *            A string that will be inserted between the elements.
	 * @return a string.
	 * @throws JsonException
	 *             If the array contains an invalid number.
	 */
	public String join(String separator) throws JsonException {
		int len = this.length();
		StringBuffer sb = new StringBuffer();

		for (int i = 0; i < len; i += 1) {
			if (i > 0) {
				sb.append(separator);
			}
			sb.append(JsonBean.valueToString(this.myArrayList.get(i), keymap, excluded));
		}
		return sb.toString();
	}
}
